package arithmetique;


/**
 * @author Chen / Yvonnic
 *
 * The Class Source represent an income
 */
public class Source {

	//the noyau of an income
	private Interval noyau;

	//the support of an income
	private Interval support;

	//the probability of an income
	private int proba;


	/**
	 * Constructor in the case 'sure'
	 * @param valeur := value : double
	 */
	public Source(double valeur) {
		this.noyau = new Interval(valeur,valeur);
		this.support = new Interval(valeur,valeur);
		this.proba = 5;
	}

	/**
	 * Constructor in the case 'unsure'
	 * @param valeur := value : double
	 * @param proba := the probability to get the income : int
	 */
	public Source(double valeur, int proba) {
		this.noyau = new Interval(valeur,valeur);
		this.support = new Interval(valeur,valeur);
		this.proba = proba;
	}

	/**
	 * Another constructor in the case 'sure'
	 * @param smin := min supoort : double
	 * @param smax := max suport : double
	 * @param nmin := min noyau : double
	 * @param nmax := max noyau : double
	 */
	public Source(double smin, double smax, double nmin, double nmax) {
		this.noyau = new Interval(nmin,nmax);
		this.support = new Interval(smin,smax);
		this.proba = 5;
	}

	/**
	 * Another constructor in the case 'unsure'
	 * @param smin := min supoort : double
	 * @param smax := max supoort : double
	 * @param nmin := min noyau : double
	 * @param nmax := min noyau : double
	 * @param proba := the probability to get this income : int
	 */
	public Source(double smin, double smax, double nmin, double nmax, int proba) {
		this.noyau = new Interval(nmin,nmax);
		this.support = new Interval(smin,smax);
		this.proba = proba;
	}

	/**
	 * A general constructor
	 * @param noyau := noyau : Interval
	 * @param support := support : Interval
	 * @param proba := probability of the source : int
	 */
	public Source(Interval noyau, Interval support, int proba) {
		this.noyau = noyau;
		this.support = support;
		this.proba = proba;
	}


	/**
	 * @return := noyau : Interval
	 */
	public Interval getNoyau() {
		return noyau;
	}

	/**
	 * @return := the probability : int
	 */
	public int getProba() {
		return proba;
	}

	/**
	 * @return := support := Interval
	 */
	public Interval getSupport() {
		return support;
	}

	/**
	 * Given a probability, find the corresponding interval in the trapezoid
	 * @param p := the possibility : int
	 * @return := the interval at the possibility p : Interval
	 */
	public Interval getAlphaCoupe(int p) {
		return new Interval(
				(noyau.getMin() - support.getMin()) * p/proba + support.getMin(),
				(double)support.getMax() - ((double)support.getMax() - (double)noyau.getMax()) * (double)p/(double)proba);
	}

	public float getY(double X, double pas) {
		double Y = 0;
		if (noyau.getMin() >= (X - pas/2 - 0.0000000000000001) && noyau.getMax() < (X + pas/2 + 0.0000000000000001)){
			Y = proba;
		} else {
			if (support.getMin() < X && X < support.getMax()) {
				if (X < noyau.getMin()){
					Y = (double)proba / ((double)noyau.getMin() - (double)support.getMin()) * (X - (double)support.getMin());
				} else if (X > noyau.getMax()){
					Y = (double)proba + (double)proba / ((double)noyau.getMax() - (double)support.getMax()) * (X - (double)noyau.getMax());
				} else {
					Y = (double)proba;
				}
			}
		}
		return (float)Y/5;
	}

	/** test if the point (X, xproba) is in the trapezoid of the source
	 * @param X
	 * @param xproba
	 * @param strict
	 * @return
	 */
	public boolean trapezoidContain(double X, float xproba, boolean noyauMin) {
		boolean retour = false;
		if (xproba == 0){
			retour = support.getMin() < X && X < support.getMax();
		} else if (xproba == proba){
			if (noyau.getMin() != noyau.getMax()){
				retour = (noyau.getMin()== X) && !noyauMin || (noyau.getMax()== X) && noyauMin || noyau.getMin() < X && X < noyau.getMax();
			}
		} else if (xproba < proba) {
			if (support.getMin() < X && X < support.getMax()) {
				if (X < noyau.getMin()){
					retour = ((float)proba / (noyau.getMin() - support.getMin()) * (X - support.getMin())) >= xproba;
				} else if (X > noyau.getMax()){
					retour = (proba + (float)proba / (noyau.getMax() - support.getMax()) * (X - noyau.getMax())) >= xproba;
				} else {
					retour = true;
				}
			}
		}
		return retour;
	}

	/**
	 * Calculate the sum of the 2 sources
	 * @param src := another source : Source
	 */
	public void plus(Source src) {
		//les calculs des 2 sources(trapezes), selon la proba
		if(proba == src.getProba()) {
			this.noyau = noyau.plus(src.getNoyau());
			this.support = support.plus(src.getSupport());
		} else if (proba > src.getProba()){
			this.noyau = src.noyau.plusNew(this.getAlphaCoupe(src.getProba()));
			this.support =  support.plus(src.getSupport());
			this.proba = src.getProba();
		} else {
			this.noyau = noyau.plus(src.getAlphaCoupe(proba));
			this.support = support.plus(src.getSupport());
		}
	}

	/**
	 * Calculate the sum of the 2 sources
	 * @param src : source : Source
	 * @return := a new source as the result
	 */
	public Source plusNew(Source src) {
		Source source;
		//les calculs des 2 sources(trapezes), selon la proba
		if(proba == src.getProba()) {
			source = new Source(noyau.plusNew(src.getNoyau()), support.plusNew(src.getSupport()), proba);
		} else if (proba > src.getProba()){
			source = new Source(src.noyau.plusNew(this.getAlphaCoupe(src.getProba())), src.support.plusNew(this.getSupport()), src.getProba());
		} else {
			source = new Source(noyau.plusNew(src.getAlphaCoupe(proba)), support.plusNew(src.getSupport()), proba);
		}
		return source;
	}

	/**
	 * @return := if the source is precis
	 */
	public boolean isPrecis(){
		return (support.getMin() == support.getMax()) ;
	}

	public Source copy(){
		return new Source(noyau.copy(), support.copy(), proba);
	}
}
